package com.hss.init;

/*
https://kaiwu.lagou.com/course/courseInfo.htm?courseId=67#/detail/pc?id=1860





这节课主要介绍了.class文件被加载到内存中所经过的详细过程，主要分3大步：装载、链接、初始化。
其中链接中又包含验证、准备、解析3小步。

1、装载：指查找字节流，并根据此字节流创建类的过程。装载过程成功的标志就是在方法区中成功创建了类所对应的 Class 对象。

2、链接：指验证创建的类，并将其解析到 JVM 中使之能够被 JVM 执行。

3、初始化：则是将标记为 static 的字段进行赋值，并且执行 static 标记的代码语句 。


什么是装载
1）ClassLoader通过一个类的全限定名（包名+类名）来查找.class文件，并生成二进制字节流：其中class字节码文件的来源不一定是.class文件，也可以是 jar 包、zip 包，甚至是来源于网络的字节流。

2）把 .class 文件的各个部分分别解析（parse）为 JVM 内部特定的数据结构，并存储在方法区。

还记得在课时 03 中介绍的 .class 文件结构吗？在这里 JVM 会将这些 .class 文件的结构转化为 JVM 内部的运行时数据结构。这点同 JSON 解析过程有点类似：如果你做过 Android 开发，
应该都使用过 GsonFormat 将后端开发返回的 JSON 结构转化为一个运行时 Bean 类，当程序运行时使用这个 Bean 类去解析处理 JSON 数据。

3）在内存中创建一个 java.lang.Class 类型的对象：

接下来程序在运行过程中所有对该类的访问都通过这个类对象，也就是这个 Class 类型的类对象是提供给外界访问该类的接口。

加载时机

一个项目经过编译之后，往往会生成大量的 .class 文件。当程序运行时，JVM 并不会一次性的将这些 .class 文件全部加载到内存中。那 JVM 是什么时候加载某 .class 文件呢？
对此，Java 虚拟机规范中并没有严格规定，不同的虚拟机实现会有不同实现。不过以下两种情况一般会对 class 进行装载操作。

1）隐式装载：在程序运行过程中，当碰到通过 new 等方式生成对象时，系统会隐式调用 ClassLoader 去装载对应的 class 到内存中；

2）显示装载：在编写源代码时，主动调用 Class.forName() 等方法也会进行 class 装载操作，这种方式通常称为显示装载。


链接 ：        验证、准备、解析。

验证：验证是链接的第一步，目的是为了确保 .class 文件的字节流中包含的信息符合当前虚拟机的要求，并且不会危及虚拟机本身的安全。
    a、文件格式检验：检验字节流是否符合 class 文件格式的规范，并且能被当前版本的虚拟机处理。 

    b、元数据检验：对字节码描述的信息进行语义分析，以保证其描述的内容符合 Java 语言规范的要求。 

    c、字节码检验：通过数据流和控制流分析，确定程序语义是合法、符合逻辑的。

    d、符号引用检验：符号引用检验可以看作是对类自身以外（常量池中的各种符号引用）的信息进行匹配性校验。


准备 这一阶段的主要目的是为类中的静态变量分配内存，并为其设置“0值”。比

    public static int value = 100;

    在准备阶段，JVM会为value分配内存，并将其设置为0。而真正的值100是在初始化阶段设置。并且此阶段进行内存分配的仅包括类变量，而不包括实例变量（实例变量将会在对象实例化时随着对象一起分配在 Java 堆中）。

    有一种情况比较特殊--静态常量，比如：

    public static final int value = 100;

    以上代码会在准备阶段就为 value 分配内存，并设置为 100。



解析

    解析是链接的最后一步，这一阶段的任务是把常量池中的符号引用转换为直接引用，也就是具体的内存地址。在这一阶段，JVM 会将常量池中的类、接口名、字段名、方法名等转换为具体的内存地址。


初始化


这是 class 加载的最后一步，这一阶段是执行类构造器<cinit>方法的过程，并真正初始化类变量。比如：

public static int value = 100;

在准备阶段 value 被分配内存并设置为 0，在初始化阶段 value 就会被设置为 100。





总结一下对象的初始化顺序如下：

静态变量/静态代码块->普通代码块->构造函数

1.父类静态变量和静态代码块；
2.子类静态变量和静态代码块；
3.父类普通成员变量和普通...

拉勾教育版权所有：https://kaiwu.lagou.com/course/courseInfo.htm?courseId=67

* */
public class InitOrder {

    public static void main(String[] args) {
        Parent c = new Child();

        System.out.println("+++++++++++++++");
        c = new Child();
    }


    static class Parent{
        static {
            System.out.println("Parent static block");
        }

        {
            System.out.println("Parent  non-static block");
        }

        public Parent() {
            System.out.println("Parent constructor");
        }
    }

    static class  Child extends Parent{
        static {
            System.out.println("Child static block");
        }

        {
            System.out.println("Child  non-static block");
        }

        public Child() {
            System.out.println("Child constructor");

        }
    }
}
